﻿// 祖孙询问.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>

using namespace std;


/*
* https://loj.ac/p/10135
http://ybt.ssoier.cn:8088/problem_show.php?pid=1557

已知一棵 n 个节点的有根树。有 m 个询问，每个询问给出了一对节点的编号 x 和 y，询问 x 与 y 的祖孙关系。

【输入】
输入第一行包括一个整数 n 表示节点个数；

接下来 n 行每行一对整数对 a 和 b 表示 a 和 b 之间有连边。如果 b 是 −1，那么 a 就是树的根；

第 n+2 行是一个整数 m 表示询问个数；

接下来 m 行，每行两个正整数 x 和 y，表示一个询问。

【输出】
对于每一个询问，若 x 是 y 的祖先则输出 1，若 y 是 x 的祖先则输出 2，否则输出 0。

【输入样例】
10
234 -1
12 234
13 234
14 234
15 234
16 234
17 234
18 234
19 234
233 19
5
234 233
233 12
233 13
233 15
233 19
【输出样例】
1
0
0
0
2
【提示】
数据范围与提示：

对于 30% 的数据，1≤n,m≤103 ；

对于 100% 的数据，1≤n,m≤4×104 ，每个节点的编号都不超过 4×104 。
*/

#include <cstdio>
#include <cstring>
#include <algorithm>


using  namespace std;

// 定义常量：最大节点数和最大边数
const int N = 40010, M = N * 2;  // N为最大节点数，M为最大边数（无向图每条边存储两次）

// 全局变量声明
int n, m;                        // n为节点数，m为询问数
int h[N], e[M], ne[M], idx;      // 邻接表存储图：h[i]表示节点i的第一条边，e[i]表示边的终点，ne[i]表示下一条边，idx为边的索引
int depth[N], fa[N][16];         // depth[i]表示节点i的深度，fa[i][j]表示节点i向上跳2^j步到达的祖先
int q[N];                        // BFS队列

/**
 * 添加无向边到邻接表
 * @param a 边的起点
 * @param b 边的终点
 */
void add(int a, int b) {
    e[idx] = b, ne[idx] = h[a], h[a] = idx++;  // 将边b添加到节点a的邻接表中
}

/**
 * 使用BFS预处理每个节点的深度和祖先信息
 * 同时使用倍增法预处理每个节点向上跳2^k步的祖先
 * @param root 树的根节点
 */
void bfs(int root) {
    // 初始化深度数组，0x3f表示无穷大
    memset(depth, 0x3f, sizeof depth);
    depth[0] = 0; depth[root] = 1;  // 设置哨兵节点深度为0，根节点深度为1

    // BFS队列初始化
    int hh = 0, tt = 0;  // hh为队列头，tt为队列尾
    q[0] = root;         // 将根节点加入队列

    while (hh <= tt) {   // 队列不为空时继续BFS
        int t = q[hh++]; // 取出队首节点

        // 遍历节点t的所有邻接节点
        for (int i = h[t]; ~i; i = ne[i]) {
            int j = e[i];  // j是t的邻接节点

            // 如果节点j的深度还未被计算（深度为无穷大）
            if (depth[j] > depth[t] + 1) {
                depth[j] = depth[t] + 1;  // 设置j的深度为t的深度+1
                q[++tt] = j;              // 将j加入队列
                fa[j][0] = t;             // 设置j的直接父节点为t

                // 使用倍增法预处理j向上跳2^k步的祖先
                for (int k = 1; k <= 15; k++) {
                    fa[j][k] = fa[fa[j][k - 1]][k - 1];  // 2^k = 2^(k-1) + 2^(k-1)
                }
            }
        }
    }
}

/**
 * 计算两个节点的最近公共祖先(LCA)
 * 使用倍增法优化，时间复杂度O(log n)
 * @param a 第一个节点
 * @param b 第二个节点
 * @return 返回a和b的最近公共祖先
 */
int lca(int a, int b) {
    // 确保a的深度不小于b的深度
    if (depth[a] < depth[b]) swap(a, b);

    // 将a向上跳，直到a和b在同一深度
    for (int k = 15; k >= 0; k--) {
        if (depth[fa[a][k]] >= depth[b]) {
            a = fa[a][k];  // a向上跳2^k步
        }
    }

    // 如果a和b已经相等，说明b是a的祖先
    if (a == b) return a;

    // 现在a和b在同一深度，同时向上跳，直到找到最近公共祖先
    for (int k = 15; k >= 0; k--) {
        if (fa[a][k] != fa[b][k]) {  // 如果向上跳2^k步后不相等，说明LCA还在更上面
            a = fa[a][k];            // a和b同时向上跳2^k步
            b = fa[b][k];
        }
    }

    // 返回a的直接父节点，这就是LCA
    return fa[a][0];
}

/**
 * 主函数：处理输入输出并解决祖孙关系查询问题
 */
int main()
{
    // 读入节点数
    scanf("%d", &n);
    int root = 0;  // 根节点编号

    // 初始化邻接表，-1表示空
    memset(h, -1, sizeof h);

    // 读入n条边，构建树
    for (int i = 0; i < n; i++) {
        int a, b;
        scanf("%d%d", &a, &b);
        if (b == -1) {
            root = a;  // 如果b为-1，说明a是根节点
        }
        else {
            add(a, b);  // 添加无向边(a,b)和(b,a)
            add(b, a);
        }
    }

    // 使用BFS预处理树的深度和祖先信息
    bfs(root);

    // 读入询问数
    scanf("%d", &m);

    // 处理每个询问
    while (m--) {
        int a, b;
        scanf("%d%d", &a, &b);  // 读入询问的两个节点

        int p = lca(a, b);      // 计算a和b的最近公共祖先

        // 根据LCA判断祖孙关系
        if (p == a) {
            puts("1");      // a是b的祖先
        }
        else if (p == b) {
            puts("2");      // b是a的祖先
        }
        else {
            puts("0");      // a和b没有祖孙关系
        }
    }
}